package com.pb.infra.oth.util;

import lombok.extern.slf4j.Slf4j;

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.time.LocalDate;
import java.time.ZoneId;
import java.util.Calendar;
import java.util.Date;

/**
 * 日期/时间处理工具类
 *
 * @author 金洋
 * @date 2021/11/17
 */
@Slf4j
public final class DateTimeUtilNew {

    /**
     * 一分钟的毫秒数
     */
    public static final long MS_OF_MINUTE = 60000L;

    /**
     * 一小时的毫秒数
     */
    public static final long MS_OF_HOUR = 3600000L;

    /**
     * 一天的毫秒数
     */
    public static final long MS_OF_DAY = MS_OF_HOUR * 24;

    /**
     * 日期格式化：yyyyMMdd
     * SimpleDateFormat存在线程安全问题，通过ThreadLocal隔离
     */
    private static final ThreadLocal<SimpleDateFormat> DATE_FMT_8 = ThreadLocal.withInitial(() ->
            new SimpleDateFormat("yyyyMMdd"));

    /**
     * 日期格式化：yyyy-MM-dd
     * SimpleDateFormat存在线程安全问题，通过ThreadLocal隔离
     */
    private static final ThreadLocal<SimpleDateFormat> DATE_FMT_10 = ThreadLocal.withInitial(() ->
            new SimpleDateFormat("yyyy-MM-dd"));

    /**
     * 日期格式化：yyyyMMddHHmmss
     * SimpleDateFormat存在线程安全问题，通过ThreadLocal隔离
     */
    private static final ThreadLocal<SimpleDateFormat> DATE_TS_FMT_14 = ThreadLocal.withInitial(() ->
            new SimpleDateFormat("yyyyMMddHHmmss"));

    /**
     * 日期格式化：yyyyMMddHHmmssSSS
     * SimpleDateFormat存在线程安全问题，通过ThreadLocal隔离
     */
    private static final ThreadLocal<SimpleDateFormat> DATE_TS_FULL_17 = ThreadLocal.withInitial(() ->
            new SimpleDateFormat("yyyyMMddHHmmssSSS"));

    /**
     * 日期格式化：yyyy-MM-dd HH:mm:ss
     * SimpleDateFormat存在线程安全问题，通过ThreadLocal隔离
     */
    private static final ThreadLocal<SimpleDateFormat> DATE_TS_FMT_19 = ThreadLocal.withInitial(() ->
            new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"));

    /**
     * 无参构造函数
     */
    public DateTimeUtilNew() {

    }

    /**
     * 转换日期类型yyyyMMdd
     *
     * @param sDate8 yyyyMMdd格式的字符串
     * @return 返回解析后的Date
     */
    public static Date parseDate8(String sDate8) {
        try {
            return DATE_FMT_8.get().parse(sDate8);
        } catch (ParseException e) {
            throw new IllegalArgumentException("日期参数格式应为yyyyMMdd");
        }
    }

    /**
     * 转换日期类型yyyy-MM-dd
     *
     * @param sDate10 yyyy-MM-dd格式的字符串
     * @return 返回解析后的Date
     */
    public static Date parseDate10(String sDate10) {
        try {
            return DATE_FMT_10.get().parse(sDate10);
        } catch (ParseException e) {
            throw new IllegalArgumentException("日期参数格式应为yyyy-MM-dd");
        }
    }

    /**
     * 转换日期类型yyyyMMddHHmmss
     *
     * @param sDateTime14 yyyyMMddHHmmss格式的字符串
     * @return 返回解析后的Date
     */
    public static Date parseDateTime14(String sDateTime14) {
        try {
            return DATE_TS_FMT_14.get().parse(sDateTime14);
        } catch (ParseException e) {
            throw new IllegalArgumentException("日期参数格式应为yyyyMMddHHmmss");
        }
    }

    /**
     * 转换日期类型yyyy-MM-dd HH:mm:ss
     *
     * @param sDateTime19 yyyy-MM-dd HH:mm:ss格式的字符串
     * @return 返回解析后的Date
     */
    public static Date parseDateTime19(String sDateTime19) {
        try {
            return DATE_TS_FMT_19.get().parse(sDateTime19);
        } catch (ParseException e) {
            throw new IllegalArgumentException("日期参数格式应为yyyy-MM-dd HH:mm:ss");
        }
    }

    /**
     * 日期格式化为 yyyyMMdd 字符串
     *
     * @param date 日期对象
     * @return 格式化后的字符串
     */
    public static String formatDate8(Date date) {
        return DATE_FMT_8.get().format(date);
    }

    /**
     * 日期格式化为 yyyy-MM-dd 字符串
     *
     * @param date 日期对象
     * @return 格式化后的字符串
     */
    public static String formatDate10(Date date) {
        return DATE_FMT_10.get().format(date);
    }

    /**
     * 日期格式化为 yyyyMMddHHmmss 字符串
     *
     * @param date 日期对象
     * @return 格式化后的字符串
     */
    public static String formatDateTime14(Date date) {
        return DATE_TS_FMT_14.get().format(date);
    }

    /**
     * 将毫秒数格式化为 yyyyMMddHHmmssSSS 字符串
     *
     * @param ms 毫秒数
     * @return 格式化后的字符串
     */
    public static String formatFullTs17(long ms) {
        return DATE_TS_FULL_17.get().format(new Date(ms));
    }

    /**
     * 日期格式化为 yyyy-MM-dd HH:mm:ss 字符串
     *
     * @param date 日期对象
     * @return 格式化后的字符串
     */
    public static String formatDateTime19(Date date) {
        return DATE_TS_FMT_19.get().format(date);
    }

    /**
     * 将毫秒数格式化为目标格式的字符串
     *
     * @param date 日期
     * @param format 格式
     * @return 格式化后的字符串
     */
    public static String format(Date date, String format) {
        return new SimpleDateFormat(format).format(date);
    }

    /**
     * 将毫秒数格式化为目标格式的字符串
     *
     * @param ms 毫秒数
     * @param format 格式
     * @return 格式化后的字符串
     */
    public static String format(long ms, String format) {
        return format(new Date(ms), format);
    }

    /**
     * 转换日期类型yyyyMMddHHmmssSSS
     *
     * @param sDateFull17 yyyyMMddHHmmssSSS格式的字符串
     * @return long 毫秒数日期
     */
    public static long parseFull17Ts(String sDateFull17) {
        try {
            return DATE_TS_FULL_17.get().parse(sDateFull17).getTime();
        } catch (ParseException e) {
            throw new IllegalArgumentException("日期参数格式应为yyyyMMddHHmmssSSS");
        }
    }

    /**
     * 获得当前日期
     *
     * @return Date 当前日期
     */
    public static Date getNowDatePart() {
        return parseDate10(formatDate10(new Date()));
    }

    /**
     * 获取当前年份
     *
     * @return int 当前年份
     */
    public static int getNowYear() {
        Calendar calendar = Calendar.getInstance();
        return calendar.get(Calendar.YEAR);
    }

    /**
     * 获取某日期的年份
     *
     * @param date 某日期
     * @return int 当前年份
     */
    public static int getYear(Date date) {
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(date);
        return calendar.get(Calendar.YEAR);
    }

    /**
     * 获取当前月份
     *
     * @return int 当前月份
     */
    public static int getNowMonth() {
        Calendar calendar = Calendar.getInstance();
        return calendar.get(Calendar.MONTH);
    }

    /**
     * 获取某日期的上一个月日期
     *
     * @param date 当前日期
     * @return Date 上一个月日期
     */
    public static Date getLastMonth(Date date) {
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(date);
        calendar.add(Calendar.MONTH, -1);
        return calendar.getTime();
    }

    /**
     * 获取当前日期（某月内第N日）
     *
     * @return int 当前日期（某月内第N日）
     */
    public static int getNowDayOfMonth() {
        Calendar calendar = Calendar.getInstance();
        return calendar.get(Calendar.DAY_OF_MONTH);
    }

    /**
     * 计算 某日期后N天
     *
     * @param date 某日期
     * @param days N天
     * @return Date 结果日期
     */
    public static Date addDay(Date date, int days) {
        return new Date(date.getTime() + days * MS_OF_DAY);
    }

    /**
     * 计算 某日期后N小时
     *
     * @param date 某日期
     * @param hours N小时
     * @return Date 结果日期
     */
    public static Date addHours(Date date, int hours) {
        return new Date(date.getTime() + hours * MS_OF_HOUR);
    }

    /**
     * 计算 某日期后N分钟
     *
     * @param date 某日期
     * @param minutes N分钟
     * @return Date 结果日期
     */
    public static Date addMinutes(Date date, long minutes) {
        return new Date(date.getTime() + minutes * MS_OF_MINUTE);
    }

    /**
     * 计算 某日期后N秒
     *
     * @param date 某日期
     * @param seconds N秒
     * @return Date 结果日期
     */
    public static Date addSeconds(Date date, long seconds) {
        return new Date(date.getTime() + seconds * 1000);
    }

    /**
     * 计算 两个日期之间的时间差（毫秒）
     *
     * @param begin 开始日期
     * @param end 结束日期
     * @return long 时间差（毫秒）
     */
    public static long getBetweenDay(Date begin, Date end) {
        ZoneId zoneId = ZoneId.systemDefault();
        LocalDate beginLocalDate = begin.toInstant().atZone(zoneId).toLocalDate();
        LocalDate endLocalDate = end.toInstant().atZone(zoneId).toLocalDate();
        return endLocalDate.toEpochDay() - beginLocalDate.toEpochDay();
    }

}
